// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: GPL-3.0-or-later

package xyz.apiote.bimba.czwek.dashboard

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.TypedArray
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.get
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import xyz.apiote.bimba.czwek.AboutActivity
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.account.AccountActivity
import xyz.apiote.bimba.czwek.dashboard.ui.home.HomeFragment
import xyz.apiote.bimba.czwek.dashboard.ui.journey.JourneyFragment
import xyz.apiote.bimba.czwek.dashboard.ui.map.MapFragment
import xyz.apiote.bimba.czwek.data.settings.SettingsRepository
import xyz.apiote.bimba.czwek.databinding.ActivityMainBinding
import xyz.apiote.bimba.czwek.onboarding.FirstRunActivity
import xyz.apiote.bimba.czwek.repo.OfflineRepository
import xyz.apiote.bimba.czwek.repo.User
import xyz.apiote.bimba.czwek.search.Query
import xyz.apiote.bimba.czwek.search.ui.results.ResultsActivity
import xyz.apiote.bimba.czwek.settings.SettingsActivity
import xyz.apiote.bimba.czwek.settings.feeds.FeedChooserActivity


class MainActivity : AppCompatActivity() {
	private lateinit var binding: ActivityMainBinding
	private lateinit var locationPermissionRequest: ActivityResultLauncher<Array<String>>

	private lateinit var permissionAsker: Fragment
	private var locationPermissionDialogShown = false
	private var lastFragment: Fragment? = null
	lateinit var viewModel: DashboardViewModel

	override fun onCreate(savedInstanceState: Bundle?) {
		enableEdgeToEdge()
		super.onCreate(savedInstanceState)
		binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		viewModel = ViewModelProvider(this)[DashboardViewModel::class.java]

		FirstRunActivity.setFirstRunDone(this)

		ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
			val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
			val l = windowInsets.displayCutout?.safeInsetLeft?.takeIf { it > 0 } ?: insets.left
			binding.navigationDrawer.updatePadding(left = l)
			windowInsets
		}

		supportFragmentManager.registerFragmentLifecycleCallbacks(
			object : FragmentLifecycleCallbacks() {
				override fun onFragmentViewCreated(
					fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?
				) {
					setNavbarIcons(f)
					super.onFragmentViewCreated(fm, f, v, savedInstanceState)
				}
			}, true
		)

		val onBackPressedCallback =
			object : OnBackPressedCallback(binding.container.isDrawerOpen(binding.navigationDrawer)) {
				override fun handleOnBackPressed() {
					binding.container.closeDrawer(binding.navigationDrawer)
				}
			}
		onBackPressedDispatcher.addCallback(onBackPressedCallback)

		binding.container.addDrawerListener(object : DrawerListener {
			override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}

			override fun onDrawerOpened(drawerView: View) {
				onBackPressedCallback.isEnabled = true
			}

			override fun onDrawerClosed(drawerView: View) {
				onBackPressedCallback.isEnabled = false
			}

			override fun onDrawerStateChanged(newState: Int) {}
		})

		setUpDrawerHeader()

		binding.navigationDrawer.setNavigationItemSelectedListener {
			when (it.itemId) {
				R.id.drawer_cities -> {
					startActivity(Intent(this, FeedChooserActivity::class.java))
				}

				R.id.drawer_settings -> {
					startActivity(Intent(this, SettingsActivity::class.java))
				}

				R.id.drawer_about -> {
					startActivity(Intent(this, AboutActivity::class.java))
				}
			}
			false
		}

		val navView: BottomNavigationView = binding.bottomNavigation
		val navHostFragment =
			supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
		val navController = navHostFragment.navController
		navView.setupWithNavController(navController)

		locationPermissionRequest = registerForActivityResult(
			ActivityResultContracts.RequestMultiplePermissions()
		) { permissions ->
			when {
				permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true ||
						permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true -> {
					when (permissionAsker) {
						is HomeFragment -> {
							showResults(Query(Query.Mode.LOCATION))
						}

						is MapFragment -> {
							(permissionAsker as MapFragment).showLocation()
						}
					}
				}

				else -> {
					if (locationPermissionDialogShown) {
						return@registerForActivityResult
					}
					MaterialAlertDialogBuilder(this).setIcon(
						AppCompatResources.getDrawable(
							this,
							R.drawable.error_gps
						)
					)
						.setTitle(getString(R.string.no_location_access))
						.setMessage(getString(R.string.no_location_message))
						.setPositiveButton(R.string.ok) { _, _ -> }
						.show()
					locationPermissionDialogShown = true
				}
			}
		}

		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
			val notificationPermissionAsked =
				PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
					NOTIFICATION_PERMISSION_ASKED, false
				)
			if (ActivityCompat.checkSelfPermission(
					this,
					Manifest.permission.POST_NOTIFICATIONS
				) != PackageManager.PERMISSION_GRANTED && !notificationPermissionAsked
			) {
				requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1)
				PreferenceManager.getDefaultSharedPreferences(this).edit {
					putBoolean(NOTIFICATION_PERMISSION_ASKED, true)
				}
			}
		}
	}

	override fun onResume() {
		super.onResume()
		setUpDrawerHeader()
	}

	fun onNavigationClicked() {
		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
			binding.container.closeDrawer(binding.navigationDrawer)
		} else {
			binding.container.openDrawer(binding.navigationDrawer)
		}
	}

	fun onGpsClicked(fragment: Fragment): Boolean {
		when (PackageManager.PERMISSION_GRANTED) {
			ContextCompat.checkSelfPermission(
				this,
				Manifest.permission.ACCESS_COARSE_LOCATION
			) -> {
				when (fragment) {
					is HomeFragment -> {
						showResults(Query(Query.Mode.LOCATION))
					}

					is MapFragment -> {
						fragment.showLocation()
					}

					is JourneyFragment -> {

					}
				}
				return true
			}

			else -> {
				permissionAsker = fragment
				locationPermissionRequest.launch(
					arrayOf(
						Manifest.permission.ACCESS_FINE_LOCATION,
						Manifest.permission.ACCESS_COARSE_LOCATION
					)
				)
				return false
			}
		}
	}

	fun onSearchClicked(text: CharSequence) {
		val settingsRepository = SettingsRepository()
		val geocodingSettings = settingsRepository.getGeocoding(this)

		val query = Query(text.toString())
		if (query.willNeedGeocoding() &&
			geocodingSettings?.useOnline != true &&
			(geocodingSettings?.useOffline != true /* || !offlineDownloaded*/)
		) {
			if (!settingsRepository.getGeocodingInfoShown(this)) {
				MaterialAlertDialogBuilder(this)
					.setIcon(R.drawable.geocoding)
					.setTitle(R.string.no_geocoding_data)
					.setMessage(R.string.no_geocoding_data_description)
					.setPositiveButton(R.string.ok) { _, _ ->
						showResults(Query(text.toString(), Query.Mode.NAME))
					}
					.show()
				settingsRepository.setGeocodingInfoShown(true, this)

				return
			} else {
				query.mode = Query.Mode.NAME
			}
		}

		showResults(query)
	}

	private fun showResults(query: Query) {
		/* todo [3.2] (ux,low) animation
			https://developer.android.com/guide/fragments/animate
			https://github.com/raheemadamboev/fab-explosion-animation-app
		*/
		startActivity(ResultsActivity.getIntent(this, query))
	}

	fun showBadge(complete: Boolean = false) {
		// FIXME is always called w/ default args
		val colourID = if (complete) {
			android.R.attr.colorPrimary
		} else {
			com.google.android.material.R.attr.colorOnSurfaceVariant
		}
		val badge = binding.bottomNavigation.getOrCreateBadge(R.id.navigation_journey)
		val a: TypedArray = theme.obtainStyledAttributes(
			R.style.Theme_Bimba, intArrayOf(colourID)
		)
		val colour = a.getColor(0, 0)
		a.recycle()
		badge.backgroundColor = colour
		badge.isVisible = true
	}

	fun hideBadge() {
		val badge = binding.bottomNavigation.getBadge(R.id.navigation_journey)
		badge?.isVisible = false
	}

	private fun setNavbarIcons(f: Fragment?) {
		binding.bottomNavigation.menu[2].setIcon(R.drawable.journey_outline)
		binding.bottomNavigation.menu[1].setIcon(R.drawable.home_outline)
		binding.bottomNavigation.menu[0].setIcon(R.drawable.map_outline)
		when (f) {
			is HomeFragment -> {
				binding.bottomNavigation.menu[1].setIcon(R.drawable.home_black)
				lastFragment = f
			}

			is JourneyFragment -> {
				binding.bottomNavigation.menu[2].setIcon(R.drawable.journey_black)
				lastFragment = f
			}

			is MapFragment -> {
				binding.bottomNavigation.menu[0].setIcon(R.drawable.map_black)
				lastFragment = f
			}

			null -> {
				binding.bottomNavigation.menu[1].setIcon(R.drawable.home_black)
			}

			else -> {
				setNavbarIcons(lastFragment)
			}
		}
	}

	private fun setUpDrawerHeader() {
		binding.navigationDrawer.getHeaderView(0).let {
			val user = User.load(this)
			it.findViewById<TextView>(R.id.display_name).text = user.getDisplayName(this)
			it.findViewById<TextView>(R.id.sub_header).apply {
				text =
					user.emailAddress ?: getString(R.string.anonymous_sub_header)
				visibility =
					if (OfflineRepository(this@MainActivity).getSuperUser()) {
						View.VISIBLE
					} else {
						View.GONE
					}
			}
			MainScope().launch {
				it.findViewById<ImageView>(R.id.avatar).setImageDrawable(user.getAvatar(this@MainActivity))
			}
			it.setOnClickListener {
				startActivity(Intent(this, AccountActivity::class.java))
			}
		}
	}

	companion object {
		const val NOTIFICATION_PERMISSION_ASKED = "notificationPermissionAsked"
	}
}
